﻿using Newtonsoft.Json;
using System.Collections;
using System.Reflection;

namespace Swimj.Core.Utilities
{
    public static class ObjectHelper
    {
        public static readonly object NULL_OBJECT = new object();

        public static readonly object[] NULL_OBJECTS = new object[0];

        public static bool IsPrimitiveArray(Type type)
        {
            return typeof(bool[]).Equals(type) ||
                typeof(sbyte[]).Equals(type) ||
                typeof(char[]).Equals(type) ||
                typeof(short[]).Equals(type) ||
                typeof(int[]).Equals(type) ||
                typeof(long[]).Equals(type) ||
                typeof(float[]).Equals(type) ||
                typeof(double[]).Equals(type);
        }


        public static bool IsArray(object obj)
        {
            if (obj == null)
            {
                return false;
            }
            return IsArray(obj.GetType());
        }

        public static bool IsArray(Type type)
        {
            if (type == null)
            {
                return false;
            }
            if (IsPrimitiveArray(type))
            {
                return true;
            }
            return ReflectionHelper.IsList(type) ||
                ReflectionHelper.IsDictionary(type) ||
                ReflectionHelper.IsCollection(type) ||
                ReflectionHelper.IsEnumerable(type) || type.IsArray;
        }

        public static object GetPropertyValue(object obj, string propertyName)
        {
            if (obj == null)
            {
                return null;
            }
            return obj.GetType().GetProperty(propertyName).GetValue(obj);
        }

        public static T GetPropertyValue<T>(object obj, string propertyName)
        {
            object propertyValue = GetPropertyValue(obj, propertyName);
            if (propertyValue == null)
            {
                return default(T);
            }
            return (T)propertyValue;
        }

        public static IList GetPropertyValues(object obj, params string[] propertyNames)
        {
            IList list = new ArrayList();
            if (obj == null)
            {
                return list;
            }
            if (propertyNames == null || propertyNames.Length <= 0)
            {
                return list;
            }
            foreach (string propertyName in propertyNames)
            {
                list.Add(obj.GetType().GetProperty(propertyName));
            }
            return list;
        }

        public static IList<object> GetListObjectPropertyValues(IList list, string propertyName)
        {
            IList<object> list2 = new List<object>();
            if (list == null || list.Count <= 0)
            {
                return list2;
            }
            foreach (object item in list)
            {
                list2.Add(GetPropertyValue(item, propertyName));
            }
            return list2;
        }

        public static IList<T> GetListObjectPropertyValues<T>(IList list, string propertyName)
        {
            IList<T> list2 = new List<T>();
            if (list == null || list.Count <= 0)
            {
                return list2;
            }
            foreach (object item in list)
            {
                list2.Add(GetPropertyValue<T>(item, propertyName));
            }
            return list2;
        }

        public static void SetPropertyValue(object obj, string propertyName, object value)
        {
            if (obj != null)
            {
                obj.GetType().GetProperty(propertyName).SetValue(obj, value);
            }
        }

        public static void SetPropertyValues(object obj, IDictionary values)
        {
            if (obj == null || values == null || values.Count <= 0)
            {
                return;
            }
            Type objType = obj.GetType();
            PropertyInfo[] propertyInfos = objType.GetProperties();
            foreach (string key in values.Keys)
            {
                object obj2 = values[key];
                if (obj2 == null)
                {
                    continue;
                }
                PropertyInfo propertyInfo = propertyInfos.Where((PropertyInfo i) => i.Name.Equals(key)).SingleOrDefault();
                if (propertyInfo != null && propertyInfo.CanWrite)
                {
                    if (propertyInfo.PropertyType.Equals(typeof(long?)) && !typeof(long).Equals(obj2.GetType()))
                    {
                        obj2 = long.Parse(obj2.ToString());
                    }
                    objType.GetProperty(key).SetValue(obj, obj2);
                }
            }
        }

        public static T ToObject<T>(IDictionary values)
        {
            Type typeFromHandle = typeof(T);
            return (T)ToObject(typeFromHandle, values);
        }

        public static object ToObject(Type objType, IDictionary values)
        {
            object obj = ReflectionHelper.CreateInstance(objType);
            SetPropertyValues(obj, values);
            return obj;
        }

        public static IList<T> ToObjects<T>(IDictionary[] entities)
        {
            List<T> list = new List<T>();
            if (entities == null || entities.Length <= 0)
            {
                return list;
            }
            foreach (IDictionary values in entities)
            {
                list.Add(ToObject<T>(values));
            }
            return list;
        }

        public static IDictionary ToDictionary(object obj)
        {
            return ToDictionary(obj, true, true, true, null, null);
        }

        public static IDictionary ToDictionaryEM(object obj, params string[] excludeMatchs)
        {
            return ToDictionary(obj, onlySimple: true, ignoreNull: true, ignoreReadableOnly: true, null, null, excludeMatchs);
        }

        public static IDictionary ToDictionary(object obj, string[] excludes)
        {
            return ToDictionary(obj, true, true, true, excludes, null);
        }

        public static IDictionary ToDictionary(object obj, string[] excludes, KeyValuePair<string, string>[] includes)
        {
            return ToDictionary(obj, true, true, true, excludes, includes);
        }

        public static IDictionary ToDictionary(object obj, KeyValuePair<string, string>[] includes)
        {
            return ToDictionary(obj, true, true, true, null, includes);
        }

        public static IDictionary ToDictionary(object obj, bool onlySimple)
        {
            return ToDictionary(obj, onlySimple, true, true, null, null);
        }

        public static IDictionary ToDictionary(object obj, bool onlySimple, bool ingoreNull)
        {
            return ToDictionary(obj, onlySimple, ingoreNull, true, null, null);
        }

        public static IDictionary ToDictionary(object obj, bool onlySimple, bool ingoreNull, bool ignoreReadableOnly)
        {
            return ToDictionary(obj, onlySimple, ingoreNull, ignoreReadableOnly, null, null);
        }

        public static IDictionary ToDictionary(object obj, bool onlySimple, bool ignoreNull, bool ignoreReadableOnly, string[] excludes)
        {
            return ToDictionary(obj, onlySimple, ignoreNull, ignoreReadableOnly, excludes, null);
        }

        public static IDictionary ToDictionary(object obj, bool onlySimple,
            bool ignoreNull, bool ignoreReadableOnly, string[] excludes,
            KeyValuePair<string, string>[] includes, params string[] excludeMatchs)
        {
            IDictionary dictionary = new Dictionary<string, object>();
            if (obj == null)
            {
                return dictionary;
            }
            string[] excludeProperties = ((excludes == null) ? new string[0] : excludes);
            string[] excludeMatchProperties = ((excludeMatchs == null) ? new string[0] : excludeMatchs);
            Type objType = obj.GetType();
            PropertyInfo[] array = objType.GetProperties();
            if (onlySimple)
            {
                array = array.Where((PropertyInfo p) => p.PropertyType.FullName.StartsWith("System") && !p.PropertyType.FullName.StartsWith("System.Collections") && !excludeProperties.Contains(p.Name) && (excludeMatchProperties.Length <= 0 || !excludeMatchProperties.Where((string e) => p.Name.StartsWith(e) || p.Name.EndsWith(e)).Any())).ToArray();
            }
            PropertyInfo[] array2 = array;
            foreach (PropertyInfo propertyInfo in array2)
            {
                if (!ignoreReadableOnly || !(propertyInfo.GetSetMethod() == null))
                {
                    object value = propertyInfo.GetValue(obj);
                    if (value != null || !ignoreNull)
                    {
                        dictionary.Add(propertyInfo.Name, value);
                    }
                }
            }
            if (includes != null)
            {
                for (int j = 0; j < includes.Length; j++)
                {
                    KeyValuePair<string, string> keyValuePair = includes[j];
                    object propertyValue = objType.GetProperty(keyValuePair.Key).GetValue(obj);
                    if (propertyValue != null || !ignoreNull)
                    {
                        dictionary.Add(keyValuePair.Value, propertyValue);
                    }
                }
            }
            return dictionary;
        }

        public static void CopyProperties(object src, object desc, params string[] excludes)
        {
            CopyProperties(src, desc, srcIgnoreNull: true, excludes);
        }

        public static void CopyProperties(object src, object dest, bool srcIgnoreNull, params string[] excludes)
        {
            CopyProperties(src, dest, srcIgnoreNull, descIgnoreNotNull: false, excludes);
        }

        public static void CopyProperties(object src, object dest, bool srcIgnoreNull, bool descIgnoreNotNull, params string[] excludes)
        {
            if (src == null || dest == null)
            {
                return;
            }
            IDictionary<string, object> dictionary = ToDictionary(src, onlySimple: true, srcIgnoreNull) as IDictionary<string, object>;
            List<string> list = new List<string>();
            if (excludes != null)
            {
                list.AddRange(excludes);
            }
            if (descIgnoreNotNull)
            {
                IDictionary<string, object> dictionary2 = ToDictionary(dest, onlySimple: true) as IDictionary<string, object>;
                list.AddRange(dictionary2.Keys);
            }
            foreach (string item in list)
            {
                if (dictionary.ContainsKey(item))
                {
                    dictionary.Remove(item);
                }
            }
            SetPropertyValues(dest, dictionary as IDictionary);
        }

        public static IDictionary<string, IList<object>> GetDifferences(object o1, object o2)
        {
            return GetDifferences(o1, o2, true, true, true, null, null);
        }

        public static IDictionary<string, IList<object>> GetDifferencesEM(object o1, object o2, params string[] excludeMatchs)
        {
            return GetDifferences(o1, o2, onlySimple: true, ignoreNull: true, ignoreReadableOnly: true, null, null, excludeMatchs);
        }

        public static IDictionary<string, IList<object>> GetDifferences(object o1, object o2, string[] excludes)
        {
            return GetDifferences(o1, o2, true, true, true, excludes, null);
        }

        public static IDictionary<string, IList<object>> GetDifferences(object o1, object o2, string[] excludes, KeyValuePair<string, string>[] includes)
        {
            return GetDifferences(o1, o2, true, true, true, excludes, includes);
        }

        public static IDictionary<string, IList<object>> GetDifferences(object o1, object o2, KeyValuePair<string, string>[] includes)
        {
            return GetDifferences(o1, o2, true, true, true, null, includes);
        }

        public static IDictionary<string, IList<object>> GetDifferences(object o1, object o2, bool onlySimple)
        {
            return GetDifferences(o1, o2, onlySimple, true, true, null, null);
        }

        public static IDictionary<string, IList<object>> GetDifferences(object o1, object o2, bool onlySimple, bool ingoreNull)
        {
            return GetDifferences(o1, o2, onlySimple, ingoreNull, true, null, null);
        }

        public static IDictionary<string, IList<object>> GetDifferences(object o1, object o2, bool onlySimple, bool ingoreNull, bool ignoreReadableOnly)
        {
            return GetDifferences(o1, o2, onlySimple, ingoreNull, ignoreReadableOnly, null, null);
        }

        public static IDictionary<string, IList<object>> GetDifferences(object o1, object o2, bool onlySimple, bool ignoreNull, bool ignoreReadableOnly, string[] excludes)
        {
            return GetDifferences(o1, o2, onlySimple, ignoreNull, ignoreReadableOnly, excludes, null);
        }

        public static IDictionary<string, IList<object>> GetDifferences(object o1, object o2, bool onlySimple, bool ignoreNull, bool ignoreReadableOnly, string[] excludes, KeyValuePair<string, string>[] includes, params string[] excludeMatchs)
        {
            if (o1 == null || o2 == null)
            {
                throw new ArgumentNullException();
            }
            IDictionary<string, IList<object>> dictionary = new Dictionary<string, IList<object>>();
            IDictionary<string, object> d2;
            if (o1 is string)
            {
                d2 = JsonConvert.DeserializeObject<IDictionary<string, object>>(o1 as string);
            }
            else
            {
                d2 = (IDictionary<string, object>)ToDictionary(o1, onlySimple, ignoreNull, ignoreReadableOnly, excludes, includes, excludeMatchs);
            }
            IDictionary<string, object> d3;
            if (o2 is string)
            {
                d3 = JsonConvert.DeserializeObject<IDictionary<string, object>>(o2 as string);
            }
            else
            {
                d3 = (IDictionary<string, object>)ToDictionary(o2, onlySimple, ignoreNull, ignoreReadableOnly, excludes, includes, excludeMatchs);
            }
            IEnumerable<KeyValuePair<string, object>> enumerable = d2.Where((KeyValuePair<string, object> d) => !d3.ContainsKey(d.Key) || !object.Equals(d.Value, d3[d.Key]));
            foreach (KeyValuePair<string, object> item in enumerable)
            {
                IList<object> list = new List<object>();
                list.Add(item.Value);
                if (d3.ContainsKey(item.Key))
                {
                    list.Add(d3[item.Key]);
                }
                else
                {
                    list.Add(string.Empty);
                }
                dictionary.Add(item.Key, list);
            }
            IEnumerable<KeyValuePair<string, object>> enumerable2 = d3.Where((KeyValuePair<string, object> d) => !d2.ContainsKey(d.Key));
            foreach (KeyValuePair<string, object> item2 in enumerable2)
            {
                IList<object> list2 = new List<object>();
                list2.Add(string.Empty);
                list2.Add(item2.Value);
                dictionary.Add(item2.Key, list2);
            }
            return dictionary;
        }
    }
}
